package com.mrx.loader.util;

import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;

import java.io.IOException;
import java.util.Objects;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * 将 jar 和 tar 之类的 Entry 转化成 Stream 操作
 * <pre>
 *     <s>虽然有点过度设计了就是, 但不想删了</s>
 * </pre>
 */
public class EntryStream implements Spliterator<BaseEntry<?>> {

    private final Supplier<BaseEntry<?>> entrySupplier;

    /**
     * 构造一个 Spliterator
     *
     * @param entrySupplier 获取下一个 entry 的方法
     */
    private EntryStream(Supplier<BaseEntry<?>> entrySupplier) {
        this.entrySupplier = entrySupplier;
    }

    /**
     * {@link StreamSupport#stream(Spliterator, boolean)} 的快捷方式
     *
     * @param entrySupplier 获取下一个 entry 的方法
     * @return 构造好的 Stream
     */
    public static Stream<BaseEntry<?>> stream(Supplier<BaseEntry<?>> entrySupplier) {
        return StreamSupport.stream(new EntryStream(entrySupplier), false);
    }

    /**
     * 构造一个用以执行 Stream 的 TarEntry
     */
    public static BaseEntry<TarArchiveEntry> getStreamTarEntry(TarArchiveInputStream tarInputStream) {
        TarArchiveEntry nextTarEntry;
        try {
            nextTarEntry = tarInputStream.getNextTarEntry();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return nextTarEntry == null ? null : new StreamTarEntry(nextTarEntry);
    }

    /**
     * 构造一个用以执行 Stream 的 JarEntry
     */
    public static BaseEntry<JarEntry> getStreamJarEntry(JarInputStream jarInputStream) {
        JarEntry nextTarEntry;
        try {
            nextTarEntry = jarInputStream.getNextJarEntry();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return nextTarEntry == null ? null : new StreamJarEntry(nextTarEntry);
    }

    @Override
    public boolean tryAdvance(Consumer<? super BaseEntry<?>> consumer) {
        Objects.requireNonNull(consumer);
        BaseEntry<?> entry = entrySupplier.get();
        if (entry != null) {
            consumer.accept(entry);
            return true;
        }
        return false;
    }

    @Override
    public Spliterator<BaseEntry<?>> trySplit() {
        return null;
    }

    @Override
    public long estimateSize() {
        return Long.MAX_VALUE;
    }

    @Override
    public int characteristics() {
        return Spliterator.ORDERED;
    }

}
